package com.yswy.app.service.impl;

import com.alipay.api.response.AlipayTradePayResponse;
import com.alipay.api.response.AlipayUserAgreementExecutionplanModifyResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yswy.app.service.AgreementOrderPayLogService;
import com.yswy.app.service.AgreementOrderService;
import com.yswy.app.service.ZfbPayKeyService;
import com.yswy.common.enums.DateUnitEnums;
import com.yswy.common.utils.DateUtils;
import com.yswy.common.utils.StringUtils;
import com.yswy.common.zfbOrder.ZfbKeyVo;
import com.yswy.common.zfbOrder.ZfbOrderUtil;
import com.yswy.domain.entity.AgreementOrder;
import com.yswy.domain.entity.AgreementOrderPayLog;
import com.yswy.domain.entity.PayOrder;
import com.yswy.domain.mapper.AgreementOrderPayLogMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class AgreementOrderPayLogServiceImpl extends ServiceImpl<AgreementOrderPayLogMapper, AgreementOrderPayLog>
        implements AgreementOrderPayLogService {
    @Autowired
    private PayOrderServiceImpl payOrderService ;
    @Autowired
    private AgreementOrderService agreementOrderService ;
    @Autowired
    private ZfbPayKeyService zfbPayKeyService ;
    @Override
    public  AgreementOrderPayLog addAgreementOrderPayLogV2(AgreementOrder agreementOrder , Integer payments , Integer paySize) {
        Long period =  agreementOrder.getPeriod();
        //周期类型，枚举值为DAY和MONTH
        String periodType =  agreementOrder.getPeriodType();
        //首次执行时间
        String executeTime = agreementOrder.getExecuteTime();
        //收款收款时间
        Integer collTime = agreementOrder.getCollTime();
        //当天收款延后时间类型
        String collTimeType = agreementOrder.getCollTimeType();
        //每期扣款次数
        Integer agreemenPayNum = agreementOrder.getAgreemenPayNum();


        Integer agreemenType = agreementOrder.getAgreemenType();
        //后续扣款价格
        Integer singleAmount = agreementOrder.getSingleAmount();


        //添加会员时间
        Long agreemenTime = agreementOrder.getPeriod();
        String agreemenTimeType = agreementOrder.getPeriodType();

        //技术扣款价格
        if(agreemenType == 0){
            singleAmount = agreementOrder.getSingleAmount();
            agreemenTime = agreementOrder.getPeriod();
            agreemenTimeType = agreementOrder.getPeriodType();
        }else {
            if (payments == 0){
                //添加会员时间
                agreemenTime = 7l;
                agreemenTimeType = DateUnitEnums.DAY.getMessage();
                singleAmount = agreementOrder.getSingleAmountOne();
            }else if (payments == 1){
                agreemenTime = 3l;
                agreemenTimeType = DateUnitEnums.MONTH.getMessage();
                singleAmount = agreementOrder.getSingleAmount();
            }
        }


        Date validTime =agreementOrder.getValidTime();

        //"是否是新手套餐 0:不是 1:是
        Boolean isDisposable = agreementOrder.getIsDisposable();
        Date executeTimeDate = null ;
        try {
            //第一期 + 是新用户套餐 + 提前收款  单独处理
            if (payments == 0 && isDisposable && StringUtils.isNotEmpty(collTimeType)){
                if (paySize >0){
                    executeTimeDate = new Date();
                }else {
                    executeTimeDate = DateUtils.addDateNum(validTime ,DateUnitEnums.HOUR.getMessage() , collTime * (paySize+1));
                }
            }else {
                //首次执行时间
                String caeateTimeStr = DateUtils.parseDateToStr(DateUtils.HH_MM_SS , validTime);
                executeTimeDate = DateUtils.getSimpleDateFormat(DateUtils.YYYY_MM_DD_HH_MM_SS).parse(executeTime+" "+caeateTimeStr);
                executeTimeDate = DateUtils.addDateNum(executeTimeDate ,periodType , period.intValue() * payments);
                Boolean isDelDay = periodType.equals(DateUnitEnums.DAY.getMessage())&& period>7 ;
                if ( isDelDay || periodType.equals(DateUnitEnums.MONTH.getMessage())){
                    executeTimeDate = DateUtils.addDateNum(executeTimeDate ,DateUnitEnums.DAY.getMessage() , -(agreemenPayNum-paySize));
                }
            }
            AgreementOrderPayLog agreementOrderPayLog = new AgreementOrderPayLog(agreementOrder.getId(),payments ,executeTimeDate  );
            agreementOrderPayLog.setAgreemenPrice(singleAmount);
            agreementOrderPayLog.setAgreemenTime(agreemenTime);
            agreementOrderPayLog.setAgreemenTimeType(agreemenTimeType);
            save(agreementOrderPayLog);
            return agreementOrderPayLog;
        }catch (Exception e){
            e.printStackTrace();
            log.info("周期付款收款任务创建失败 id +" +agreementOrder.getId() );
            return  null ;
        }




    }

    @Override
    public void addLastAgreementOrder(AgreementOrderPayLog agreementOrderPayLog) {
        AgreementOrder agreementOrder = agreementOrderService.getById(agreementOrderPayLog.getAgreementOrderId());

        if (agreementOrderPayLog.getStatusType() == 1){
            //扣款成功判断 创建下一期签约任务
            if (agreementOrder.getTotalPayments() == agreementOrderPayLog.getPayments()+1){
                log.info(agreementOrder.getAgreementNo()+"周期扣款期数达到上限 不创建下期扣款任务");
                return;
            }
            addAgreementOrderPayLogV2(agreementOrder,agreementOrderPayLog.getPayments()+1 ,0  );

            log.info(agreementOrder.getAgreementNo()+"创建第"+
                    (agreementOrderPayLog.getPayments()+1)+"期第"+0+"次扣款任务");
        }else {
            //扣款失败
            Integer count = count(new LambdaQueryWrapper<AgreementOrderPayLog>()
                    .eq(AgreementOrderPayLog::getAgreementOrderId , agreementOrderPayLog.getAgreementOrderId())
                    .ne(AgreementOrderPayLog::getStatusType, 1)
                    .eq(AgreementOrderPayLog::getPayments , agreementOrderPayLog.getPayments()));
            //判断扣款时间是否大于签约时间
            Boolean istrue = true ;
            try {
                SimpleDateFormat simpleDateFormat  = DateUtils.getSimpleDateFormat(DateUtils.YYYY_MM_DD_HH_MM_SS);
                Date date = simpleDateFormat.parse(agreementOrder.getExecuteTime()+ " 23:59:59");
                //添加扣款期数
                if (agreementOrderPayLog.getPayments() > 0){
                    date = DateUtils.addDateNum(date ,agreementOrder.getPeriodType()
                            , agreementOrder.getPeriod().intValue()*agreementOrderPayLog.getPayments());
                }
                if (date.before(new Date())){
                    istrue = false;
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
            if (count <= agreementOrder.getAgreemenPayNum() && istrue){
                //继续本期扣款
                addAgreementOrderPayLogV2(agreementOrder , agreementOrderPayLog.getPayments() , count);
                log.info(agreementOrder.getAgreementNo()+"创建第"+
                        (agreementOrderPayLog.getPayments())+"期第"+count+1+"次扣款任务");
            }else {
                if (agreementOrder.getTotalPayments() == agreementOrderPayLog.getPayments()+1){
                    log.info(agreementOrder.getAgreementNo()+"周期扣款期数达到上限 不创建下期扣款任务");
                    return;
                }
                try {
                    ZfbKeyVo zfbKeyVo =zfbPayKeyService.getZfbKeyVo(agreementOrder.getZfbId() , null);
                    Long Period = (agreementOrderPayLog.getPayments()+1)*agreementOrder.getPeriod();
                    Date deductTime = DateUtils.getSimpleDateFormat(DateUtils.YYYY_MM_DD).parse(agreementOrder.getExecuteTime());
                    deductTime = DateUtils.addDateNum(deductTime ,agreementOrder.getPeriodType() , Period.intValue());
                    String deduct_time = DateUtils.getSimpleDateFormat(DateUtils.YYYY_MM_DD).format(deductTime);
                    //延期扣款
                    AlipayUserAgreementExecutionplanModifyResponse response = ZfbOrderUtil.AlipayUserAgreementExecutionplanModifyRequest( zfbKeyVo ,  deduct_time
                            , "扣款失败执行下期扣款",agreementOrder.getAgreementNo());
                    log.info(agreementOrder.getAgreementNo()+" : 状态" +response.getSubCode() );
                    if (response.getSubCode().equals("USER_AGREEMENT_NOT_EXIST")){
                        log.info(agreementOrder.getAgreementNo()+"协议不存在");
                        agreementOrder.setStatus(4);
                        agreementOrder.setStatusType("UNSIGN");
                        agreementOrderService.updateById(agreementOrder);
                        return;
                    }else {
                        log.info(agreementOrder.getAgreementNo()+"执行延期扣款 ——返回"+
                                response.getSubMsg() +"  "
                                +response.getMsg()+"  "
                                +response.getSubCode()
                                +"  "+response.getSubCode()
                                +"  "+response.getBody());
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                //创建下一期扣款任务
                addAgreementOrderPayLogV2(agreementOrder , agreementOrderPayLog.getPayments()+1 , 0);
                log.info(agreementOrder.getAgreementNo()+"创建第"+
                        (agreementOrderPayLog.getPayments()+1)+"期第"+0+"次扣款任务");
            }
        }

    }

    @Override
    public void addLastAgreementOrder(PayOrder payOrder) {
        AgreementOrderPayLog agreementOrderPayLog  = getOne(new LambdaQueryWrapper<AgreementOrderPayLog>()
                .eq(AgreementOrderPayLog::getPayOrderId , payOrder.getId()));
        addLastAgreementOrder(agreementOrderPayLog);
    }

    @Override
    public void addAgreementOrderPayLog(AgreementOrder agreementOrder) {
        List<AgreementOrderPayLog> agreementOrderPayLogs = new ArrayList<>();

        //周期类型，枚举值为DAY和MONTH
        String periodType =  agreementOrder.getPeriodType();
        //扣款周期
        Long period = agreementOrder.getPeriod();
        //首次执行时间
        String executeTime = agreementOrder.getExecuteTime();
        //总扣款次数
        Integer  totalPayments = agreementOrder.getTotalPayments();
        //收款收款时间
        Integer collTime = agreementOrder.getCollTime();
        //当天收款延后时间类型
        String collTimeType = agreementOrder.getCollTimeType();
        //每期扣款次数
        Integer agreemenPayNum = agreementOrder.getAgreemenPayNum();
        Date createTime =agreementOrder.getCreateTime();
        //"是否是新手套餐 0:不是 1:是
        Boolean isDisposable = agreementOrder.getIsDisposable();
        Date executeTimeDate = null ;

        for (int i = 0; i < totalPayments; i++) {
            if (isDisposable && i == 0 ){
                executeTimeDate = createTime ;
                for (int j = 1; j <= agreemenPayNum; j++) {
                    if (collTimeType.equals(DateUnitEnums.DAY.getMessage())){
                        if (j == 1) {
                            executeTimeDate = DateUtils.addDateNum(executeTimeDate ,collTimeType , collTime);
                        }else {
                            executeTimeDate = DateUtils.addDateNum(executeTimeDate ,collTimeType , 1);
                        }
                    }else {
                        executeTimeDate = DateUtils.addDateNum(executeTimeDate ,collTimeType , collTime);
                    }
                    try {
                        if (!executeTimeDate.before(
                                DateUtils.getSimpleDateFormat(DateUtils.YYYY_MM_DD_HH_MM_SS).parse(executeTime+" 23:59:59"))){
                            break;
                        }
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    agreementOrderPayLogs.add(new AgreementOrderPayLog(agreementOrder.getId(),i ,executeTimeDate  ));
                }
            }else {
                String caeateTimeStr = DateUtils.parseDateToStr(DateUtils.HH_MM_SS , createTime);
                executeTime = executeTime+" "+caeateTimeStr;
                try {
                    executeTimeDate = DateUtils.getSimpleDateFormat(DateUtils.YYYY_MM_DD_HH_MM_SS).parse(executeTime);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                Integer integer = i*period.intValue() ;
//                if (isDisposable){
//                    integer = (i-1)*period.intValue() ;
//                }
                executeTimeDate = DateUtils.addDateNum(executeTimeDate ,periodType, integer);
                for (int j = 0; j < agreemenPayNum; j++) {
                    if (j >0){
                        if (periodType.equals(DateUnitEnums.DAY.getMessage())){
                            executeTimeDate = DateUtils.addDateNum(executeTimeDate ,DateUnitEnums.DAY.getMessage() , -1);
                        }else if (periodType.equals(DateUnitEnums.MONTH.getMessage())){
                            executeTimeDate = DateUtils.addDateNum(executeTimeDate ,DateUnitEnums.DAY.getMessage() , -1);
                        }
                    }
                    agreementOrderPayLogs.add(new AgreementOrderPayLog(agreementOrder.getId(),i ,executeTimeDate  ));
                }
            }
        }
        saveBatch(agreementOrderPayLogs);
    }





    public static void main(String[] args) throws ParseException {

        try {
            SimpleDateFormat simpleDateFormat  = DateUtils.getSimpleDateFormat(DateUtils.YYYY_MM_DD_HH_MM_SS);
            SimpleDateFormat simpleDateFormat1  = DateUtils.getSimpleDateFormat(DateUtils.YYYY_MM_DD_HH_MM_SS);
            Date date = simpleDateFormat.parse("2023-06-24 23:59:59");
            System.out.println(simpleDateFormat.format(date));;
            System.out.println(simpleDateFormat1.format(new Date()));;
            System.out.println(date.getTime());;
            System.out.println(new Date().getTime());;

//            Calendar calendar = Calendar.getInstance();
//            date.setTime("2023-06-24 23:59:59");

            if (date.before(new Date())){
                System.out.println(1111);
            }else {
                System.out.println(222);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }

//        List<AgreementOrderPayLog> agreementOrderPayLogs = new ArrayList<>();
//        AgreementOrder agreementOrder = new AgreementOrder();
//        //付款周期
//        agreementOrder.setPeriod(3l);
//        //付款周期类型，枚举值为DAY和MONTH
//        agreementOrder.setPeriodType(DateUnitEnums.MONTH.getMessage());
//        //executeTime
//        agreementOrder.setExecuteTime("2023-06-21");
//        agreementOrder.setValidTime(new Date());
//        //收款收款时间
//        agreementOrder.setCollTime(2);
////        当天收款延后时间类型
//        agreementOrder.setCollTimeType("DAY");
//        //每期扣款次数
//        agreementOrder.setAgreemenPayNum(3);
//        agreementOrder.setValidTime(new Date());
//        //"是否是新手套餐 0:不是 1:是
//        agreementOrder.setIsDisposable(true);
////        AgreementOrderPayLog agreementOrderPayLog = addAgreementOrderPayLogV2(agreementOrder ,0 , 0 );
////        agreementOrderPayLogs.add(agreementOrderPayLog);
//        int i = 0 ;
//        int paySize = 0 ;
//        while (true){
//            System.out.println(i + "  "+ paySize);
//            Integer random = (int)(Math.random()*100)+1 ;
//            if (random  >= 90){
//                AgreementOrderPayLog agreementOrderPayLog = addAgreementOrderPayLogV2(agreementOrder ,i , paySize );
//                agreementOrderPayLogs.add(agreementOrderPayLog);
//                //收款成功
//                i++;
//            }else {
//                AgreementOrderPayLog agreementOrderPayLog = addAgreementOrderPayLogV2(agreementOrder ,i , paySize );
//                agreementOrderPayLogs.add(agreementOrderPayLog);
//                paySize++;
//
//            }
//
//            if (paySize>=3){
//                i++;
//                paySize = 0;
////                System.out.println("延期");
////                Date date = DateUtils.getSimpleDateFormat(DateUtils.YYYY_MM_DD_HH_MM_SS).parse(agreementOrder.getExecuteTime()+" 00:00:00");
////                date = DateUtils.addDateNum(date ,DateUnitEnums.DAY.getMessage() , 1);
////                agreementOrder.setExecuteTime( DateUtils.getSimpleDateFormat(DateUtils.YYYY_MM_DD).format(date));
////                agreementOrder.setValidTime(DateUtils.addDateNum(agreementOrder.getValidTime() ,DateUnitEnums.DAY.getMessage() , 1));
//            }
//            if (i>=10){
//                break;
//            }
//        }
//
//
//
//        for (AgreementOrderPayLog a:
//        agreementOrderPayLogs) {
//            System.out.println(a.getPayments() +"  "+
//                    DateUtils.getSimpleDateFormat(DateUtils.YYYY_MM_DD_HH_MM_SS).format(a.getTimeDate()));
//        }
    }

    @Override
    public void unAgreementOrderPayLog(Long agreementOrderId) {
        update(new LambdaUpdateWrapper<AgreementOrderPayLog>()
                .eq(AgreementOrderPayLog::getStatusType, -1)
                .eq(AgreementOrderPayLog::getAgreementOrderId , agreementOrderId)
                .set(AgreementOrderPayLog::getStatusType, 3));
    }

    @Override
    public void userAgreementPayOrder() {
        int pageNum = 1;
        int pageSize = 10;
        boolean hasMore = true;
        while (hasMore) {
            //获取今天的日期

            Date date = new Date();
            // 查询第 pageNum 页数据
            Page<AgreementOrderPayLog> resultPage = baseMapper.selectPage(new Page<>(pageNum, pageSize)
                    , Wrappers.<AgreementOrderPayLog>lambdaQuery()
                            .le(AgreementOrderPayLog::getTimeDate  , date)
                            .eq(AgreementOrderPayLog::getStatusType , -1));
            List<AgreementOrderPayLog> dataList = resultPage.getRecords();
            
            if(dataList.size() == 0)break;
            // 判断是否还有数据
            if (dataList.size() == pageSize) {
                pageNum++;
            } else {
                hasMore = false;
            }
            
            
            // 处理数据
            List<AgreementOrderPayLog> updateDataList = resultPage.getRecords();
            for (AgreementOrderPayLog agreementOrderPayLog : dataList) {
                //判断本期是否扣款
                Integer count = count(new LambdaQueryWrapper<AgreementOrderPayLog>()
                        .eq(AgreementOrderPayLog::getAgreementOrderId , agreementOrderPayLog.getAgreementOrderId())
                        .eq(AgreementOrderPayLog::getStatusType, 1)
                        .eq(AgreementOrderPayLog::getPayments , agreementOrderPayLog.getPayments()));
                AgreementOrder agreementOrder = agreementOrderService.getById(agreementOrderPayLog.getAgreementOrderId());
                if (count<=0){
                    //扣款
                    PayOrder payOrder = payOrderService.addAgreementOrder(agreementOrder , agreementOrderPayLog);

                    AlipayTradePayResponse response =  payOrder.getResponse();
                    if(response.isSuccess()){
                        update(new LambdaUpdateWrapper<AgreementOrderPayLog>()
                                .set(AgreementOrderPayLog::getStatusType , 0)
                                .set(AgreementOrderPayLog::getPayOrderId ,payOrder.getId() )
                                .eq(AgreementOrderPayLog::getLogId,agreementOrderPayLog.getLogId()));
                    } else {
                        update(new LambdaUpdateWrapper<AgreementOrderPayLog>()
                                .set(AgreementOrderPayLog::getStatusType , 5)
                                .eq(AgreementOrderPayLog::getLogId,agreementOrderPayLog.getLogId()));
                    }
//                    updateDataList.add(agreementOrderPayLog);
                }else {
                    //本期已扣款成功 ， 修改本期计划
                    update(new LambdaUpdateWrapper<AgreementOrderPayLog>()
                            .eq(AgreementOrderPayLog::getAgreementOrderId , agreementOrderPayLog.getAgreementOrderId())
                            .eq(AgreementOrderPayLog::getStatusType, -1)
                            .eq(AgreementOrderPayLog::getPayments , agreementOrderPayLog.getPayments())
                            .set(AgreementOrderPayLog::getStatusType , 4));
                }
            }
//            updateBatchById(updateDataList);

        }
    }

    @Override
    public void userAgreementPayOrderV2() {
        int pageNum = 1;
        int pageSize = 10;
        boolean hasMore = true;
        while (hasMore) {
            //获取今天的日期
            Date date = new Date();
            // 查询第 pageNum 页数据
            Page<AgreementOrderPayLog> resultPage = baseMapper.selectPage(new Page<>(pageNum, pageSize)
                    , Wrappers.<AgreementOrderPayLog>lambdaQuery()
                            .le(AgreementOrderPayLog::getTimeDate  , date)
                            .eq(AgreementOrderPayLog::getStatusType , -1));
            List<AgreementOrderPayLog> dataList = resultPage.getRecords();

            if(dataList.size() == 0)break;
            // 判断是否还有数据
            if (dataList.size() == pageSize) {
                pageNum++;
            } else {
                hasMore = false;
            }
            // 处理数据
            for (AgreementOrderPayLog agreementOrderPayLog : dataList) {
                try {
                    AgreementOrder agreementOrder = agreementOrderService.getById(agreementOrderPayLog.getAgreementOrderId());
                    //扣款
                    PayOrder payOrder = payOrderService.addAgreementOrder(agreementOrder , agreementOrderPayLog);
                    if (payOrder == null){
                        update(new LambdaUpdateWrapper<AgreementOrderPayLog>()
                                .set(AgreementOrderPayLog::getStatusType , 5)
                                .set(AgreementOrderPayLog::getSubMsg,"用户不存在")
                                .eq(AgreementOrderPayLog::getLogId,agreementOrderPayLog.getLogId()));
                    }
                    AlipayTradePayResponse response =  payOrder.getResponse();
                    if(payOrder.getOrderStatus() == 0){
                        //扣款成功
                        update(new LambdaUpdateWrapper<AgreementOrderPayLog>()
                                .set(AgreementOrderPayLog::getStatusType , 0)
                                .set(AgreementOrderPayLog::getPayOrderId ,payOrder.getId() )
                                .eq(AgreementOrderPayLog::getLogId,agreementOrderPayLog.getLogId()));
                        //创建下一期扣款任务
//                    addAgreementOrderPayLogV2(agreementOrder , agreementOrderPayLog.getPayments()+1 , 0);
                    } else {
                        update(new LambdaUpdateWrapper<AgreementOrderPayLog>()
                                .set(AgreementOrderPayLog::getStatusType , 5)
                                .set(AgreementOrderPayLog::getSubMsg,response.getSubMsg()+response.getSubCode())
                                .set(AgreementOrderPayLog::getPayOrderId ,payOrder.getId())
                                .eq(AgreementOrderPayLog::getLogId,agreementOrderPayLog.getLogId()));
                        agreementOrderPayLog.setStatusType(5);
                        if (response.getSubCode().equals("ACQ.AGREEMENT_NOT_EXIST")){
                            log.info("AgreementOrderPayLog:" +payOrder.getOrderId()+"  "+response.getSubMsg() );
                        }else if (response.getSubCode().equals("ACQ.CYCLE_PAY_DATE_NOT_MATCH")){
                            //扣款时间不在签约时间
                            addLastAgreementOrder(agreementOrderPayLog);
                        }else {
                            //扣款失败
                            //判断是否继续执行本期扣款
                            addLastAgreementOrder(agreementOrderPayLog);
                        }
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }

            }
        }
    }


}
